package othello.client.playroom;

import gwt.canvas.client.Canvas;

import java.util.List;

import othello.client.service.OthelloService;
import othello.client.service.OthelloServiceAsync;
import othello.client.utility.screen.Screen;
import othello.client.utility.screen.ScreenManager;
import othello.shared.model.GameStep;

import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;

/**
 * <p>
 * オセロ対局画面を実装するGWTウィジット
 * </p>
 * 
 * @author onjiro.mohyahya
 */
class Othello extends Composite {

	private static OthelloUiBinder uiBinder = GWT.create(OthelloUiBinder.class);

	interface OthelloUiBinder extends UiBinder<Widget, Othello> {
	}

	/**
	 * オセロ・リモートサービスのプロキシ
	 */
	private final OthelloServiceAsync service = GWT
			.create(OthelloService.class);

	private GameBoard boardModel;

	private int count = 0;

	@UiField
	Canvas mainCanvas;

	/**
	 * コンストラクター
	 * 
	 * @param boardModel
	 *            使用されるゲーム盤のモデル
	 */
	public Othello(String boardId, GameStep.Side mySide) {
		this.boardModel = new GameBoard(boardId, mySide);

		// UIバインダーからのウィジットの読み込み
		initWidget(uiBinder.createAndBindUi(this));
		mainCanvas.setWidth(640);
		mainCanvas.setHeight(480);

		// TODO ロード中、何らかの失敗時のダイアログを表示

		// TODO 現在のゲームボードのモデルを読み込み
		this.service.getStepsFrom(boardId, 0,
				new AsyncCallback<List<GameStep>>() {
					public void onSuccess(List<GameStep> result) {
						for (GameStep step : result) {
							boardModel.apply(step);
						}
					};

					public void onFailure(Throwable caught) {
						Window.alert("Fail!! OthelloService#getStepsFrom");
					};
				});

		// 画像、設定の読み込み
		final ImageSettings settings = new ImageSettingsDefault();

		// 画像読み込みの完了時点でゲーム盤のビューを作成、更新タイマーのセットをするためのタイマー実装
		new Timer() {
			private static final int UPDATE_INTERVAL = 1000 / 30;

			@Override
			public void run() {
				if (settings.isLoadCompleted()) {

					ViewForGameBoard boardActor = new ViewForGameBoard(
							boardModel, settings);
					final ScreenManager manager = new ScreenManager(new Screen(
							mainCanvas));
					manager.entry(boardActor);

					// ビューの更新ループ用タイマーを設定。
					// DeferredCommandではCPUが占有されてしまうため、Timerにて実装
					new Timer() {
						public void run() {
							if (manager.updateScreen()) {
								this.schedule(UPDATE_INTERVAL);
							}
						};
					}.schedule(UPDATE_INTERVAL);

					// すべてのロードが完了した時点で状態を変更して入力の受付を開始する。
					ControllerForGameBoard controller = new ControllerForGameBoard(
							boardModel, service, mainCanvas, settings);
					manager.entry(controller.getView());

					// 読み込みが完了したらリピートをキャンセル
					this.cancel();
				}
				count++;
				new Label(String.valueOf(count));
			}
		}.scheduleRepeating(2000);

		// 相手ターン時に一定時間毎に更新をチェックするタイマーのセット
		new Timer() {
			@Override
			public void run() {
				try {
					if (boardModel.isMyTurn()) {
						return;
					}
					service.getStepsFrom(boardModel.getId(), boardModel
							.getCurrentStep(),
							new AsyncCallback<List<GameStep>>() {
								@Override
								public void onSuccess(List<GameStep> result) {
									for (GameStep step : result) {
										boardModel.apply(step);
									}
								}

								@Override
								public void onFailure(Throwable caught) {
									Window.alert("failed to check update.");
								}
							});
				} finally {
					this.schedule(3000);
				}
			}
		}.schedule(5000);

	}
}
